package ctrl

import (
	// "im/util"
	"encoding/json"
	"log"
	"net"
	"net/http"
	"strconv"
	"sync"

	"github.com/fatih/set"
	"github.com/gorilla/websocket"
)

const (
	MSG_SINGLE = 10
	MSG_ROOM   = 11
	MSG_HEART  = 0
)

type Node struct {
	Conn      *websocket.Conn
	DataQueue chan []byte
	GroupSets set.Interface
}

type Message struct {
	Id      int64  `json:"id,omitempty" form:"id"`             // 消息ID
	UserId  int64  `json:"user_id,omitempty" form:"user_id"`   // 谁发的
	MsgType uint8  `json:"msg_type,omitempty" form:"msg_type"` // 群聊还是私聊
	DstId   int64  `json:"dst_id,omitempty" form:"dst_id"`     // 对端用户ID/群ID
	Media   uint8  `json:"media,omitempty" form:"media"`       // 消息按照什么样式展示
	Content string `json:"content,omitempty" form:"content"`   // 消息的内容
	Pic     string `json:"pic,omitempty" form:"pic"`           // 预览图片
	Url     string `json:"url,omitempty" form:"url"`           // 服务的URL
	Memo    string `json:"memo,omitempty" form:"memo"`         // 简单描述
	Amount  int    `json:"amount,omitempty" form:"amount"`     // 其他和数字相关的
}

var rwlocker sync.RWMutex

var clientMap map[int64]*Node = make(map[int64]*Node, 0)

func Chat(w http.ResponseWriter, r *http.Request) {
	query := r.URL.Query()
	userId, err := strconv.ParseInt(query.Get("id"), 10, 64)
	if err != nil {
		log.Println(48, err)
	}
	// 验证token
	conn, err := (&websocket.Upgrader{
		CheckOrigin: func(r *http.Request) bool {
			return checkToken(userId, query.Get("token"))
		},
	}).Upgrade(w, r, nil)
	if err != nil {
		log.Println(56, err)
        return
	}
	node := &Node{
		Conn:      conn,
		DataQueue: make(chan []byte, 50),
		GroupSets: set.New(set.ThreadSafe),
	}
	// 获取用户群
	communitys := contactService.SearchComunity(userId)
	for _, v := range communitys {
		node.GroupSets.Add(v)
	}
	rwlocker.Lock()
	clientMap[userId] = node
	rwlocker.Unlock()
	// 协程发送消息
	go send(node)
	// 协程接收消息
	go recv(node)
}

func checkToken(userId int64, token string) bool {
	user := userService.Find(userId)
	return user.Token == token
}

func send(node *Node) {
	for {
		select {
		case data := <-node.DataQueue:
			err := node.Conn.WriteMessage(websocket.TextMessage, data)
			if err != nil {
				log.Println(83, err)
			}
		}
	}
}

func recv(node *Node) {
	for {
		_, data, err := node.Conn.ReadMessage()
		if err != nil {
			log.Println(92, err)
			return
		}
		// dispatch(data)
        broadMsg(data)
	}
}

func sendMsg(userId int64, msg []byte) {
	rwlocker.RLock()
	node, ok := clientMap[userId]
	rwlocker.RUnlock()
	if ok {
		node.DataQueue <- msg
	}
}

// 消息转发处理
func dispatch(data []byte) {
	msg := Message{}
	err := json.Unmarshal(data, &msg)
	if err != nil {
		log.Println(112, err)
		return
	}
	switch msg.MsgType {
	case MSG_SINGLE:
		sendMsg(msg.DstId, data)
	case MSG_ROOM:
		for _, v := range clientMap {
			if v.GroupSets.Has(msg.DstId) {
				v.DataQueue <- data
			}
		}
	case MSG_HEART:
	}
}

// 加群
func AddGroup(userId, DstId int64) {
	rwlocker.Lock()
	node, ok := clientMap[userId]
	if ok {
		node.GroupSets.Add(DstId)
	}
	rwlocker.Unlock()
}

var udpsendchan chan []byte = make(chan []byte, 1024)

func broadMsg(data []byte) {
    udpsendchan <- data
}

func udpsendproc() {
    log.Println("start udpsendproc")
    conn, err := net.DialUDP("udp", nil, &net.UDPAddr{
        IP: net.IPv4(192, 168, 0, 255),
        Port: 3000,
    })
    if err != nil {
        log.Println(err)
        return
    }
    defer conn.Close()
    for {
        select {
        case data := <- udpsendchan:
            _, err := conn.Write(data)
            if err != nil {
                log.Println(err)
                return
            }
        }
    }
}

func udprecvproc() {
    log.Println("start udprecvproc")
    conn, err := net.ListenUDP("udp", &net.UDPAddr{
        IP: net.IPv4zero,
        Port: 3000,
    })
    if err != nil {
        log.Println(err)
        return
    }
    defer conn.Close()
    for {
        var buf [512]byte
        n, err := conn.Read(buf[0:])
         if err != nil {
            log.Println(err)
            return
        }
        dispatch(buf[0: n])
        log.Println("stop udprecvproc")
    } 
}

func init() {
    go udpsendproc()
    go udprecvproc()
}
